﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
using System.Threading;

namespace WPFInterview.Threading
{
    /// <summary>
    /// Interaction logic for ThreadingQuestion.xaml
    /// </summary>
    public partial class ThreadingQuestion : UserControl
    {
        private static Object monitorObject = new Object();

        private delegate void UpdateProgressDelegate(int progressID, int progress);

        UpdateProgressDelegate updateMethod;

        void UpdateProgress(int progressID, int progress)
        {
            Monitor.Enter(monitorObject);
            // we need to make sure exclusive access to the code below
            if (progressID == 0) _threadProgress1.Value = progress;
            else if (progressID == 1) _threadProgress2.Value = progress;
            else if (progressID == 2) _threadProgress3.Value = progress;
            else if (progressID == 3) _threadProgress4.Value = progress;
            else if (progressID == 4) _threadProgress5.Value = progress;
            Monitor.Exit(monitorObject);
        }

        public ThreadingQuestion()
        {
            InitializeComponent();

            // Register the delegate
            updateMethod += UpdateProgress;
        }

        private void WorkerThread(Object o)
        {
            int id = (int)o;
            int counter = 0;
            while (counter < 100)
            {
                // Sleep one second
                Thread.Sleep(1000);

                // Increase the counter
                switch(id)
                {
                    case 1: counter+=3;
                        break;
                    case 2: counter += 5;
                        break;
                    case 3: counter += 7;
                        break;
                    case 4: counter += 9;
                        break;
                    case 5: counter += 10;
                        break;
                    default:
                        counter += 10;
                        break;
                }               

                // Update GUI
                Application.Current.Dispatcher.BeginInvoke(updateMethod, id, counter);
            }
        }

        /// <summary>
        /// Input the progress ID
        /// </summary>
        /// <param name="i"></param>
        private void CreateThreads()
        {
            // 5 threads
            Thread[] threads = new Thread[5];

            // Generate a thread start.
            ParameterizedThreadStart operation = new ParameterizedThreadStart(WorkerThread);
            for (int i = 0; i < 5; i++)
            {
                // Start five thread at a time.
                threads[i] = new Thread(operation);

                // make sure it is a background thread. Otherwise, no update to the GUI is possible.
                threads[i].IsBackground = true;

                // Start the thread with the progress ID
                threads[i].Start(i);
            }

            bool isCompleted = false;
            foreach (Thread t in threads)
            {
                // One of the thread is completed, let us abort other threads.
                if (!t.IsAlive)
                {
                    isCompleted = true;
                }

                if (isCompleted && !t.IsAlive) t.Abort();
            }
            
            //foreach (Thread t in threads)
            //{
            //    t.Join();
            //}

        }

        private void Grid_Loaded(object sender, RoutedEventArgs e)
        {
            CreateThreads();
        }
    }

    public class ThreadingTest : IQuestion
    {
        public string TestName
        {
            get { return "Threading - Multiple threads"; }
        }

        public UserControl getUserControl()
        {
            return new ThreadingQuestion();
        }
    }
}
